/*
 * Copyright 2010, The PLDesktop Development Team
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */
#ifndef PLLISTITERATOR_H
#define PLLISTITERATOR_H

#include <tools/PLIListIterator.h>

namespace PLSDK {
    
    /**
     * The iterator for lists.
     */
    template<typename T>
    class PLListIterator
    {
    public:
        /**
         * Constructor.
         */
        inline PLListIterator() : m_current(0), m_first(0), m_iterator(0) {}
        /**
         * Constructor.
         *
         * @param _iterator Iterator from the list.
         * @param _current The first node.
         */
        inline PLListIterator(PLIListIterator<T> *_iterator, PLListNode<T> *_current) : m_current(_current), m_first(_current), m_iterator(_iterator) {}
        /**
         * Copy constructor.
         *
         * @param it The iterator to copy.
         */
        inline PLListIterator(const PLListIterator<T> &it) : m_current(it.m_current), m_first(it.m_first), m_iterator(it.m_iterator) {}
        /**
         * Have the current position have a next object.
         *
         * @return true if the current position have a next object.
         */
        inline bool hasNext() {
            return m_iterator->hasNext(m_current);
        }
        /**
         * Have the current position have a previous object.
         *
         * @return true if the current position have a previous object.
         */
        inline bool hasPrevious() {
            return m_iterator->hasPrevious(m_current);
        }
        /**
         * The next object from the list.
         *
         * @return The next object from the list.
         */
        inline T next();
        /**
         * The current object from the list.
         *
         * @return The current object from the list.
         */
        inline T current() {
            return m_current->content();
        }
        /**
         * Get the current node of the iterator.
         *
         * @return The current node of the iterator.
         */
        inline PLListNode<T> &currentNode() {
            return *m_current;
        }
        /**
         * Add a object into the list at the current position.
         *
         * @param object The object to add to the list.
         */
        inline void add(T *object);
        /**
         * Remove the current object from the list.
         */
        inline void remove();
        /**
         * Reset the iterator to the first object.
         */
        inline void reset() {
            m_current = m_first;
        }
        /**
         * Is the iterator not on the position with the node.
         *
         * @param node The node to test for.
         * @return True if it was not that position.
         */
        inline bool operator != (PLListNode<T> *node);
        /**
         * Is the iterator on the position with the node.
         *
         * @param node The node to test for.
         * @return True if it was that position.
         */
        inline bool operator == (PLListNode<T> *node);
    private:
        PLListNode<T> *m_current;
        PLListNode<T> *m_first;
        PLIListIterator<T> *m_iterator;
    };

    /**
     * Compare a list iterator with a list node.
     */
    template<typename T>
    bool operator != (PLListIterator<T> &it, const PLListNode<T> &node);

    /**
     * Compare a list iterator with a list node.
     */
    template<typename T>
    bool operator == (PLListIterator<T> &it, const PLListNode<T> &node);

    template<typename T>
    T PLListIterator<T>::next() {
        T o = m_iterator->next(m_current);
        m_current = m_current->next();
        return o;
    }

    template<typename T>
    void PLListIterator<T>::add(T *object) {
        m_iterator->add(object, m_current);
        m_current = m_current->getNext();
    }

    template<typename T>
    void PLListIterator<T>::remove() {
        m_current = m_iterator->remove(m_current);
    }

    template<typename T>
    bool PLListIterator<T>::operator != (PLListNode<T> *node) {
        if(m_current != node) {
            return true;
        }
        return false;
    }

    template<typename T>
    bool PLListIterator<T>::operator == (PLListNode<T> *node) {
        if(m_current == node) {
            return true;
        }
        return false;
    }

    template<typename T>
    bool operator != (PLListIterator<T> &it, const PLListNode<T> &node) {
        if(it.currentNode() != node) {
            return true;
        }
        return false;
    }

    template<typename T>
    bool operator == (PLListIterator<T> &it, const PLListNode<T> &node) {
        if(it.currentNode() == node) {
            return true;
        }
        return false;
    }

}

#endif
